﻿using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using Catel.Articles.Base.Data.Attributes;
using Catel.Data;

namespace Catel.Articles.Base.Data
{
    #region Delegates
    /// <summary>
    /// Delegate without parameters and return value.
    /// </summary>
    public delegate void VoidDelegate();
    #endregion

    /// <summary>
    /// ExampleInfo Data object class which fully supports serialization, property changed notifications,
    /// backwards compatibility and error checking.
    /// </summary>
    [Serializable]
    public class ExampleInfo : DataObjectBase<ExampleInfo>
    {
        #region Variables
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new instance of the <see cref="ExampleInfo"/> class.
        /// </summary>
        /// <param name="exampleAttribute">The example attribute.</param>
        public ExampleInfo(ExampleAttribute exampleAttribute)
            : this(exampleAttribute.Name, exampleAttribute.ShortDescription, exampleAttribute.LongDescription,
            !string.IsNullOrEmpty(exampleAttribute.ImageUri) ? new Uri(exampleAttribute.ImageUri, UriKind.RelativeOrAbsolute) : null,
            exampleAttribute.SourceFileName) { }

        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="shortDescription">The short description.</param>
        /// <param name="longDescription">The long description.</param>
        public ExampleInfo(string name, string shortDescription, string longDescription)
            : this(name, shortDescription, longDescription, null) { }

        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="shortDescription">The short description.</param>
        /// <param name="longDescription">The long description.</param>
        /// <param name="imageUri">The image URI.</param>
        public ExampleInfo(string name, string shortDescription, string longDescription, Uri imageUri)
            : this(name, shortDescription, longDescription, imageUri, null, null) { }

        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="shortDescription">The short description.</param>
        /// <param name="longDescription">The long description.</param>
        /// <param name="imageUri">The image URI.</param>
        /// <param name="sourceFileName">Relative file name of the source file.</param>
        public ExampleInfo(string name, string shortDescription, string longDescription, Uri imageUri, string sourceFileName)
            : this(name, shortDescription, longDescription, imageUri, sourceFileName, null) { }

        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="shortDescription">The short description.</param>
        /// <param name="longDescription">The long description.</param>
        /// <param name="imageUri">The image URI.</param>
        /// <param name="sourceFileName">Relative file name of the source file.</param>
        /// <param name="clickHandler">The click handler.</param>
        public ExampleInfo(string name, string shortDescription, string longDescription, Uri imageUri, string sourceFileName, VoidDelegate clickHandler)
        {
            // Store values
            Name = name;
            ShortDescription = shortDescription;
            LongDescription = longDescription;
            ImageUri = imageUri;
            ClickHandler = clickHandler;

            // Make sure to set a valid long description
            if (string.IsNullOrEmpty(LongDescription))
            {
                LongDescription = shortDescription;
            }

            try
            {
                if (!string.IsNullOrEmpty(sourceFileName))
                {
                    // Load code
                    Code = File.ReadAllText(ExampleInfoHelper.GetFullFilename(sourceFileName));
                }
            }
            catch (Exception)
            {
                // Do not do anything here
            }
        }

        /// <summary>
        /// Initializes a new object based on <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
        /// <param name="context"><see cref="StreamingContext"/>.</param>
        public ExampleInfo(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the name of the example.
        /// </summary>
        public string Name
        {
            get { return GetValue<string>(NameProperty); }
            private set { SetValue(NameProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData NameProperty = RegisterProperty("Name", typeof(string), string.Empty);

        /// <summary>
        /// Gets or sets the short description of the example.
        /// </summary>
        public string ShortDescription
        {
            get { return GetValue<string>(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData DescriptionProperty = RegisterProperty("ShortDescription", typeof(string), string.Empty);

        /// <summary>
        /// Gets or sets the long description.
        /// </summary>
        public string LongDescription
        {
            get { return GetValue<string>(LongDescriptionProperty); }
            set { SetValue(LongDescriptionProperty, value); }
        }

        /// <summary>
        /// Register the LongDescription property so it is known in the class.
        /// </summary>
        public static readonly PropertyData LongDescriptionProperty = RegisterProperty("LongDescription", typeof(string), string.Empty);

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        public string Code
        {
            get { return GetValue<string>(CodeProperty); }
            set { SetValue(CodeProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData CodeProperty = RegisterProperty("Code", typeof(string), string.Empty);

        /// <summary>
        /// Gets or sets the image Uri.
        /// </summary>
        public Uri ImageUri
        {
            get { return GetValue<Uri>(ImageUriProperty); }
            set { SetValue(ImageUriProperty, value); }
        }

        /// <summary>
        /// Register the ImageUri property so it is known in the class.
        /// </summary>
        public static readonly PropertyData ImageUriProperty = RegisterProperty("ImageUri", typeof(Uri), null);

        /// <summary>
        /// Gets or sets the method that will be invoked when the button is clicked.
        /// </summary>
        public VoidDelegate ClickHandler
        {
            get { return GetValue<VoidDelegate>(ClickHandlerProperty); }
            set { SetValue(ClickHandlerProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData ClickHandlerProperty = RegisterProperty("ClickHandler", typeof(VoidDelegate), null);
        #endregion

        #region Methods
        #endregion
    }

    /// <summary>
    /// ExampleInfo helper class.
    /// </summary>
    public static class ExampleInfoHelper
    {
        /// <summary>
        /// Gets the full filename of a relative file.
        /// </summary>
        /// <param name="relativeFilename">The relative filename.</param>
        /// <returns>The full filename.</returns>
        public static string GetFullFilename(string relativeFilename)
        {
            // Get full path
            return IO.Path.GetFullPath(relativeFilename, Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
        }
    }
}
